/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is ART Ontology API.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2009.
 * All Rights Reserved.
 *
 * The ART Ontology API were developed by the Artificial Intelligence Research Group
 * (art.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about the ART Ontology API can be obtained at 
 * http//art.uniroma2.it/owlart
 *
 */

/*
 * Contributor(s): Armando Stellato stellato@info.uniroma2.it
 */
package it.uniroma2.art.owlart.models.impl;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.exceptions.UnavailableResourceException;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.BaseRDFTripleModel;
import it.uniroma2.art.owlart.models.RDFSModel;
import it.uniroma2.art.owlart.models.RDFSReasoner;
import it.uniroma2.art.owlart.navigation.ARTLiteralIterator;
import it.uniroma2.art.owlart.navigation.ARTResourceIterator;
import it.uniroma2.art.owlart.navigation.ARTStatementIterator;
import it.uniroma2.art.owlart.navigation.ARTURIResourceIterator;
import it.uniroma2.art.owlart.utilities.RDFIterators;
import it.uniroma2.art.owlart.vocabulary.RDF;
import it.uniroma2.art.owlart.vocabulary.RDFS;

public class RDFSModelImpl extends RDFModelImpl implements RDFSModel, RDFSReasoner {

	private boolean subPropertyReasoning;
	private boolean subPropertyOfClosure;
	private boolean subClassOfClosure;

	public RDFSModelImpl(BaseRDFTripleModel baseRep) {
		super(baseRep);

		// REASONING CONFIGURATION
		if (baseRep instanceof RDFSReasoner) {
			subPropertyReasoning = ((RDFSReasoner) baseRep).supportsSubPropertyMaterialization();
			subPropertyOfClosure = ((RDFSReasoner) baseRep).supportsSubPropertyOfClosure();
			subClassOfClosure = ((RDFSReasoner) baseRep).supportsSubClassOfClosure();
		} else {
			subPropertyReasoning = false;
			subPropertyOfClosure = false;
			subClassOfClosure = false;
		}
	}

	/****************************
	 * /* ADD/REMOVE METHODS ***
	 ****************************/

	public void addComment(ARTResource subject, String label, String language, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.addTriple(subject, RDFS.Res.COMMENT, baseRep.createLiteral(label, language), graphs);
	}

	public void addLabel(ARTResource subject, String label, String language, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.addTriple(subject, RDFS.Res.LABEL, baseRep.createLiteral(label, language), graphs);
	}

	public void addClass(String uri, ARTResource... graphs) throws ModelUpdateException {
		ARTURIResource newClass = baseRep.createURIResource(uri);
		baseRep.addTriple(newClass, RDF.Res.TYPE, RDFS.Res.CLASS, graphs);
	}

	public void addPropertyDomain(ARTURIResource property, ARTResource domain, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.addTriple(property, RDFS.Res.DOMAIN, domain, graphs);
	}

	public void addPropertyRange(ARTURIResource property, ARTResource range, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.addTriple(property, RDFS.Res.RANGE, range, graphs);
	}

	public void addSuperClass(ARTResource cls, ARTResource supercls, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.addTriple(cls, RDFS.Res.SUBCLASSOF, supercls, graphs);
	}

	public void addSuperProperty(ARTURIResource property, ARTURIResource superProperty, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.addTriple(property, RDFS.Res.SUBPROPERTYOF, superProperty, graphs);
	}

	public void removeComment(ARTResource subject, String label, String language, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.deleteTriple(subject, RDFS.Res.COMMENT, baseRep.createLiteral(label, language), graphs);
	}

	public void removeLabel(ARTResource subject, String label, String language, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.deleteTriple(subject, RDFS.Res.LABEL, baseRep.createLiteral(label, language), graphs);
	}

	public void removePropertyDomain(ARTURIResource property, ARTResource domain, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.deleteTriple(property, RDFS.Res.DOMAIN, domain, graphs);
	}

	public void removePropertyRange(ARTURIResource property, ARTResource range, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.deleteTriple(property, RDFS.Res.RANGE, range, graphs);
	}

	public void removeSuperClass(ARTResource cls, ARTResource supercls, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.deleteTriple(cls, RDFS.Res.SUBCLASSOF, supercls, graphs);
	}

	public void removeSuperProperty(ARTResource property, ARTResource superProp, ARTResource... graphs)
			throws ModelUpdateException {
		baseRep.deleteTriple(property, RDFS.Res.SUBPROPERTYOF, superProp, graphs);
	}

	/*************************
	 * /* BOOLEAN METHODS ***
	 *************************/

	public boolean isClass(ARTResource cls, ARTResource... graphs) throws ModelAccessException {
		return baseRep.hasTriple(cls, RDF.Res.TYPE, RDFS.Res.CLASS, true, graphs);
	}

	/*************************
	 * /* RETRIEVE METHODS ***
	 * 
	 * @throws ModelAccessException
	 * @throws UnavailableResourceException
	 *************************/

	public ARTURIResource retrieveClass(String uri, ARTResource... graphs) throws ModelAccessException {
		ARTStatementIterator statIt = baseRep.listStatements(baseRep.createURIResource(uri), RDF.Res.TYPE,
				RDFS.Res.CLASS, true, graphs);
		if (statIt.streamOpen()) {
			ARTURIResource cls = statIt.next().getSubject().asURIResource();
			statIt.close();
			return cls;
		} else {
			statIt.close();
			return null;
		}
	}

	/*************************
	 * /* LIST/GET METHODS ***
	 *************************/

	public ARTLiteralIterator listComments(ARTResource res, boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return new LiteralIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(res, RDFS.Res.COMMENT, NodeFilters.ANY, inferred, graphs)));
	}

	public ARTLiteralIterator listLabels(ARTResource res, boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return new LiteralIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(res, RDFS.Res.LABEL, NodeFilters.ANY, inferred, graphs)));
	}

	public ARTURIResourceIterator listPropertiesForDomainClass(ARTResource cls, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new URIResourceIteratorWrappingResourceIterator(new SubjectsOfStatementsIterator(
				baseRep.listStatements(NodeFilters.ANY, RDFS.Res.DOMAIN, cls, inferred, graphs)));
	}

	public ARTURIResourceIterator listPropertiesForRangeClass(ARTResource cls, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new URIResourceIteratorWrappingResourceIterator(new SubjectsOfStatementsIterator(
				baseRep.listStatements(NodeFilters.ANY, RDFS.Res.RANGE, cls, inferred, graphs)));
	}

	public ARTResourceIterator listPropertyDomains(ARTResource property, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new ResourceIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(property, RDFS.Res.DOMAIN, NodeFilters.ANY, inferred, graphs)));
	}

	public ARTResourceIterator listPropertyRanges(ARTResource property, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new ResourceIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(property, RDFS.Res.RANGE, NodeFilters.ANY, inferred, graphs)));
	}

	public ARTResourceIterator listSubClasses(ARTResource cls, boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return new SubjectsOfStatementsIterator(baseRep.listStatements(NodeFilters.ANY, RDFS.Res.SUBCLASSOF,
				cls, inferred, graphs));
	}

	public ARTResourceIterator listSuperClasses(ARTResource cls, boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return new ResourceIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(cls, RDFS.Res.SUBCLASSOF, NodeFilters.ANY, inferred, graphs)));
	}

	public ARTURIResourceIterator listSubProperties(ARTURIResource property, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new URIResourceIteratorWrappingResourceIterator(new SubjectsOfStatementsIterator(
				baseRep.listStatements(NodeFilters.ANY, RDFS.Res.SUBPROPERTYOF, property, inferred, graphs)));
	}

	public ARTURIResourceIterator listSuperProperties(ARTURIResource property, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new URIResourceIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(property, RDFS.Res.SUBPROPERTYOF, NodeFilters.ANY, inferred, graphs)));
	}

	public ARTURIResourceIterator listNamedClasses(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		if (inferred && supportsSubClassOfClosure()) {
			return RDFIterators.filterURIs(RDFIterators.listSubjects(baseRep.listStatements(NodeFilters.ANY,
					RDF.Res.TYPE, RDFS.Res.RESOURCE, true, graphs)));
		} else {
			System.out.println("inside the listNamedClasses of RDFSModel");
			return RDFIterators.listDistinct(RDFIterators.filterURIs(RDFIterators.listSubjects(RDFIterators
					.createARTStatementIterator(RDFIterators.concat(baseRep.listStatements(NodeFilters.ANY,
							RDF.Res.TYPE, RDFS.Res.CLASS, inferred, graphs), baseRep.listStatements(
							NodeFilters.ANY, RDFS.Res.SUBCLASSOF, NodeFilters.ANY, inferred, graphs))))));
		}
	}

	public ARTURIResourceIterator listNamedResources(ARTResource... graphs) throws ModelAccessException {
		if (supportsSubClassOfClosure()) {
			return new URIResourceIteratorFilteringResourceIterator(new SubjectsOfStatementsIterator(
					baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE, RDFS.Res.RESOURCE, true, graphs)));
		} else {
			return RDFIterators.listDistinct(RDFIterators.filterURIs(RDFIterators
					.listSubjects(listStatements(NodeFilters.ANY, NodeFilters.ANY, NodeFilters.ANY, false,
							graphs))));
		}
	}

	public ARTURIResourceIterator listURISuperClasses(ARTResource cls, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		return new URIResourceIteratorFilteringNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(cls, RDFS.Res.SUBCLASSOF, NodeFilters.ANY, inferred, graphs)));
	}

	/*************************
	 * /* RENAME METHODS ***
	 * 
	 * @throws ModelUpdateException
	 * @throws ModelAccessException
	 *************************/

	public void renameClass(ARTURIResource cls, String newURI) throws ModelUpdateException {
		renameIndividual(cls, newURI);
	}

	/******************************
	 *** RDFS REASONING METHODS ***
	 ******************************/

	public boolean supportsSubPropertyMaterialization() {
		return subPropertyReasoning;
	}

	public boolean supportsSubPropertyOfClosure() {
		return subPropertyOfClosure;
	}

	public boolean supportsSubClassOfClosure() {
		return subClassOfClosure;
	}

}
